package com.tools.demo.login.secret;


import com.tools.demo.login.secret.exception.RsaException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * RSA公钥对象
 * @author Haviven
 * @since 2021/9/16
 **/
public class RsaPublicKey implements RsaEncode {

    private final PublicKey publicKey;

    /**
     * 指定publicKey创建RSAPublicKey对象
     * @param publicKey publicKey
     */
    public RsaPublicKey(PublicKey publicKey) {
        this.publicKey = publicKey;
    }

    /**
     * 指定publicKey字符串创建RSAPublicKey对象
     * @param publicKey publicKey
     */
    public RsaPublicKey(String publicKey) {
        try {
            byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes());
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            this.publicKey = keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 加密
     * @param content 被加密内容
     * @return 加密内容
     */
    @Override
    public byte[] encrypt(byte[] content) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, this.publicKey);
            return cipher.doFinal(content);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 加密
     * @param content 被加密内容
     * @return 加密内容
     */
    @Override
    public String encrypt(String content) {
        try {
            return new String(Base64.getEncoder().encode(encrypt(content.getBytes(RsaEncode.CHARSET))));
        } catch (UnsupportedEncodingException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 解密
     * @param content 被解密内容
     * @return 解密内容
     */
    @Override
    public byte[] decrypt(byte[] content) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            return cipher.doFinal(content);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 解密
     * @param content 被解密内容
     * @return 解密内容
     */
    @Override
    public String decrypt(String content){
        try {
            return new String(decrypt(Base64.getDecoder().decode(content)), RsaEncode.CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 验签
     * @param content 被验签内容
     * @param sign 签名
     * @return 是否正确
     */
    public boolean verify(byte[] content, byte[] sign) {
        try {
            Signature signature = Signature.getInstance(RsaEncode.SIGNATURE_INSTANCE);
            signature.initVerify(publicKey);
            signature.update(content);
            return signature.verify(sign);
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 验签
     * @param content 被验签内容
     * @param sign 签名
     * @return 是否正确
     */
    public boolean verify(String content, String sign) {
        try {
            return verify(content.getBytes(RsaEncode.CHARSET), Base64.getDecoder().decode(sign));
        } catch (UnsupportedEncodingException e) {
            throw new RsaException(e);
        }
    }

    /**
     * 获取PublicKey
     * @return PublicKey
     */
    public PublicKey getPublicKey() {
        return publicKey;
    }

    /**
     * 获取PublicKey密钥
     * @return publicKey密钥
     */
    @Override
    public String getKey() {
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }

}
